Some things I've come across while on my JS Algorithms and Data Structures kick on FCC:
Although I've come across the following before I haven't put some into much use sooo let the jot down commence!
Passing a string within the brackets, WhateverHere['followers']
vs. WhateverHere[followers]
.
The former allows variable to be passed and evaluated as a property name. Man, I forget quotations on properties more than I'd like to admit.
let users = {
Alan: {
age: 27,
online: false
},
Jeff: {
age: 32,
online: true
},
Sarah: {
age: 48,
online: false
},
Ryan: {
age: 19,
online: true
}
};
function countOnline(obj) {
let count = 0;
for(let user in users) {
console.log(users[user].online);
if(users[user].online == true) {
count++;
}
}
return count;
}
console.log(countOnline(users));
Object.keys
:let users = {
Alan: {
age: 27,
online: false
},
Jeff: {
age: 32,
online: true
},
Sarah: {
age: 48,
online: false
},
Ryan: {
age: 19,
online: true
}
};
function getArrayOfUsers(obj) {
return Object.keys;
}
console.log(getArrayOfUsers(users));
The following created a basic Dog object, where 'lab' creates a new instance of Dog.
function Dog(name, color) {
this.name = name,
this.color = color,
this.numLegs = 4
}
let lab = new Dog('rodi', 'brown);
Preventing duplicates in instances:
function Dog(name) {
this.name = name;
}
// prevents numerous var duplicates in instances created, below prototype is obj shared among all instances
Dog.prototype.numLegs = 4;
let beagle = new Dog('Snoopy');
console.log(beagle.numLegs);
own
prop vs. prototype
prop:
function Dog(name) {
this.name = name; // own prop
}
Dog.prototype.numLegs = 4; // prototype prop
let beagle = new Dog('Snoopy');
let ownProps = [];
let prototypeProps = [];
for(let prop in beagle) {
if(beagle.hasOwnProperty(prop)) {
ownProps.push(prop);
}
else {
prototypeProps.push(prop);
}
}
efficiency; add props:
function Dog(name) {
this.name = name;
}
// add props to prototype at once instead of individually
Dog.prototype = {
numLegs: 2,
eat: function() {
console.log('Nom');
},
describe: function() {
console.log(`Bark! My name is ${this.name}`)
}
}
side-effect on manually setting up prototype on new obj: ^ it erases constructor
function Dog(name) {
this.name(name);
}
Dog.prototype = {
constructor: Dog, // the fix: define constructor prop
numLegs: 2,
eat: function() {
console.log('nom nom nom');
},
describe: function() {
console.log(`My name is ${this.name}`);
}
}
let beagle = new Dog();
console.log(beagle.constructor);
where obj prototype comes from:
function Dog(name) {
this.name = name;
}
let beagle = new Dog('Snoopy);
// obj inherits its prototype from constructor function that created it
Dog.prototype.isPrototypeOf(beagle); // returns true
supertypes: dog is supertype of beagle (subtype) Object is supertype of Dog AND beagle
.hasOwnProperty
is defined in Object.prototype, able to be accessed across 'prototype chain'
Object is supertype for all objects in JS, any object can use .hasOwnProperty
method
function Dog(name) {
this.name = name;
}
let beagle = new Dog('Snoopy');
Dog.prototype.isPrototypeOf(beagle); // => true
Object.prototype.isPrototypeOf(Dog.prototype); // => true
keeping things DRY: the eat method was moved to Animal supertype instead of being repeated twice in Cat and Bear
function Cat(name) {
this.name = name;
}
Cat.prototype = {
constructor: Cat,
}
function Bear(name) {
this.name = name;
}
Bear.prototype = {
constructor: Bear,
}
function Animal() {}
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log('nom nom nom');
}
}
alternative to new
in creating instances:
let animal = Object.create(Animal.prototype)
Object.create(obj)
creates a new object and sets obj
as new object's prototype. Rememebering that prototype is like a 'formula' for creating an object-- setting prototype of animal
to be Animal's prototype-- you are giving animal
instance the same 'formula' as any instance of Animal
.
animal.eat(); // prints 'nom nom nom'
animal instanceof Animal; // => true
a bit more fleshed out example:
function Animal() {}
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log('nom nom nom');
}
}
let duck = Object.create(Animal.prototype);
let beagle = Object.create(Animal.prototype);
duck.eat(); // should print 'nom nom nom'
beagle.eat();
setting prototype of subtype(child):
function Animal() {}
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log('nom nom nom');
}
}
function Dog() {}
/**
sets prototype of subtype (child), Dog, to be instance of Animal
prototype is like 'formula' for creating object; Dog now includes all 'steps/ingredients' from Animal;
beagle inherits Animal props including eat method
**/
Dog.prototype = Object.create(Animal.prototype);
let beagle = new Dog();
beagle.eat(); // should print 'nom nom nom'
When object inherits its prototype from another object, it also inherits supertype's constructor prop.
However, beagle and all instances of Dog should show that they were constructed by Dog, not Animal.
The fix: manually set Dog's constructor prop to Dog object, same for duck
function Animal() {}
function Bird() {}
function Dog() {}
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
let duck = new Bird();
Bird.prototype.constructor = Bird;
duck.constructor
let beagle - new Dog();
Dog.prototype.constructor = Dog;
dog.constructor
adding methods after inheritance:
function Animal() {}
Animal.prototype.eat = function() { console.log('nom nom nom'); }
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('woof!');
}
let beagle = new Dog();
beagle.eat(); // should print 'nom nom nom'
beagle.bark(); // should print 'woof!'
above adds behavior that is unique to Dog obj
When you have an instance let greyhound = new Dog();
and call greyhound.eat()
, JavaScript looks for the method on greyhound prototype
chain.
Something like:
function Bird() {}
Bird.prototype.fly = function() { return 'flyyyyyying'; };
function Penguin() {}
// inherits all methods from Bird
Penguin.prototype = Object.create(Bird.prototype);
Penguin.prototype.constructor = Penguin;
// Penguin.fly() overrides Bird.fly()
Penguin.prototype.fly = function() { return 'Alas, I am flightess.'; };
let penguin = new Penguin();
console.log(penguin.fly());
A bird and boat can both glide, yet are not both animals...
let bird = {
name: 'Daffy',
numLegs: 2
}
let boat = {
name: 'Pegasus',
type: 'cruiser'
}
let glideMixin = function(obj) {
obj.glide = function() {
return 'glidin'
}
}
glideMixin(bird);
glideMixin(boat);
The advantage of the module
pattern, behaviors can be packaged into single object able to be reused by other parts of code.
motionModule.glideMixin(duck);
duck.glide();
function Bird() {
let weight = 15; // private prop
// publicaly accessible method that any bird obj can use
this.getWeight = function() {
return weight;
}
}
function has no name, anonymous, not stored in a variable-- the parenthesis at the end causes it to be executed right away
(function() {
console.log('I get executed right away!');
})();
advantage: all behaviors packaged into single obj
from this:
let isCuteMixin = function(obj) {
obj.isCute = function() {
return true;
}
}
let singMixin = function(obj) {
obj.sing = function() {
console.log('singin my own tune')
}
}
to this:
let funModule = (function() {
return {
isCuteMixin: function(obj) {
obj.isCute = function() {
return true;
}
},
singMixin: function(obj) {
obj.sing = function() {
console.log('singin my own tune')
}
}
}
})();